//****************************************************
// Porman Project 2
// Filename: CWordSystem.cpp
// Date: 2009/08/09
// Author: KengYu Lin
// Modify:
//****************************************************
#include <fstream>
#include "CRenderDevice.h"
#include "CWordSystem.h"
#include "ASCIITexture.h"

namespace Porman
{

namespace GL
{

//-----------------------------
// class CTGAImg
//-----------------------------
CTGAImg::CTGAImg()
{ 
	m_pImage = m_pPalette = m_pData = NULL;
	m_iWidth = m_iHeight = m_iBPP = m_bEnc = 0;
	m_lImageSize=0;
}

CTGAImg::~CTGAImg()
{
	if(m_pImage)
	{
		delete [] m_pImage;
		m_pImage=NULL;
	}

	if(m_pPalette)
	{
		delete [] m_pPalette;
		m_pPalette=NULL;
	}

	if(m_pData)
	{
		delete [] m_pData;
		m_pData=NULL;
	}
}

int CTGAImg::load(const char* szFilename)
{
	using namespace std;
	ifstream fIn;
	unsigned long ulSize;
	int iRet;

	// Clear out any existing image and palette
	if(m_pImage)
	{
		delete [] m_pImage;
		m_pImage=NULL;
	}

	if(m_pPalette)
	{
		delete [] m_pPalette;
		m_pPalette=NULL;
	}

	// Open the specified file
	fIn.open(szFilename,ios::binary);

	if(fIn==NULL)
		return IMG_ERR_NO_FILE;

	// Get file size
	fIn.seekg(0,ios_base::end);
	ulSize=fIn.tellg();
	fIn.seekg(0,ios_base::beg);

	// Allocate some space
	// Check and clear pDat, just in case
	if(m_pData)
		delete [] m_pData; 

	m_pData=new unsigned char[ulSize];

	if(m_pData==NULL)
	{
		fIn.close();
		return IMG_ERR_MEM_FAIL;
	}

	// Read the file into memory
	fIn.read((char*)m_pData,ulSize);

	fIn.close();

	// Process the header
	iRet=_readHeader();

	if(iRet!=IMG_OK)
		return iRet;

	switch(m_bEnc)
	{
	case 1: // Raw Indexed
		{
			// Check filesize against header values
			if((m_lImageSize+18+m_pData[0]+768)>ulSize)
				return IMG_ERR_BAD_FORMAT;

			// Double check image type field
			if(m_pData[1]!=1)
				return IMG_ERR_BAD_FORMAT;

			// Load image data
			iRet=_loadRawData();
			if(iRet!=IMG_OK)
				return iRet;

			// Load palette
			iRet=_loadTgaPalette();
			if(iRet!=IMG_OK)
				return iRet;

			break;
		}

	case 2: // Raw RGB
		{
			// Check filesize against header values
			if((m_lImageSize+18+m_pData[0])>ulSize)
				return IMG_ERR_BAD_FORMAT;

			// Double check image type field
			if(m_pData[1]!=0)
				return IMG_ERR_BAD_FORMAT;

			// Load image data
			iRet=_loadRawData();
			if(iRet!=IMG_OK)
				return iRet;

			_BGRtoRGB(); // Convert to RGB
			break;
		}

	case 9: // RLE Indexed
		{
			// Double check image type field
			if(m_pData[1]!=1)
				return IMG_ERR_BAD_FORMAT;

			// Load image data
			iRet=_loadTgaRLEData();
			if(iRet!=IMG_OK)
				return iRet;

			// Load palette
			iRet=_loadTgaPalette();
			if(iRet!=IMG_OK)
				return iRet;

			break;
		}

	case 10: // RLE RGB
		{
			// Double check image type field
			if(m_pData[1]!=0)
				return IMG_ERR_BAD_FORMAT;

			// Load image data
			iRet=_loadTgaRLEData();
			if(iRet!=IMG_OK)
				return iRet;

			_BGRtoRGB(); // Convert to RGB
			break;
		}

	default:
		return IMG_ERR_UNSUPPORTED;
	}

	// Check flip bit
	if((m_pData[17] & 0x20)==0) 
		flipImg();

	// Release file memory
	delete [] m_pData;
	m_pData=NULL;

	return IMG_OK;
}

void CTGAImg::flipImg() // Flips the image vertically (Why store images upside down?)
{
	unsigned char bTemp;
	unsigned char *pLine1, *pLine2;
	int iLineLen,iIndex;

	iLineLen=m_iWidth*(m_iBPP/8);
	pLine1=m_pImage;
	pLine2=&m_pImage[iLineLen * (m_iHeight - 1)];

	for( ;pLine1<pLine2;pLine2-=(iLineLen*2))
	{
		for(iIndex=0;iIndex!=iLineLen;pLine1++,pLine2++,iIndex++)
		{
			bTemp=*pLine1;
			*pLine1=*pLine2;
			*pLine2=bTemp;       
		}
	} 
}

int CTGAImg::getBPP() 
{
	return m_iBPP;
}

int CTGAImg::getWidth()
{
	return m_iWidth;
}

int CTGAImg::getHeight()
{
	return m_iHeight;
}

unsigned char* CTGAImg::getImg()
{
	return m_pImage;
}

unsigned char* CTGAImg::getPalette()
{
	return m_pPalette;
}

// Warning!!
// Original image will lost.
bool CTGAImg::downSampling()
{
	if ( m_iWidth==1 && m_iHeight==1 )
		return false; // no more

	int bytes_per_pixel = m_iBPP/8;
	int newWidth = m_iWidth / 2;
	int newHeight = m_iHeight / 2;

	if ( newWidth < 1 ) newWidth = 1;
	if ( newHeight < 1 ) newHeight = 1;

	unsigned char *pNewImage = new unsigned char[newWidth*newHeight*bytes_per_pixel];
	unsigned char *pDest = pNewImage;

	for (int y=0; y<newHeight; y++ )
	{
		for ( int x=0; x<newWidth; x++ )
		{
			unsigned char *p0 = _getPixel(x*2, y*2);
			unsigned char *p1 = _getPixel(x*2+1, y*2  );
			unsigned char *p2 = _getPixel(x*2  , y*2+1);
			unsigned char *p3 = _getPixel(x*2+1, y*2+1);

			for ( int i=0; i<bytes_per_pixel; i++ )
			{
				pDest[i] = (p0[i] + p1[i] + p2[i] + p3[i])/4;
			}
			
			pDest += bytes_per_pixel;
		}
	}

	delete [] m_pImage;

	m_pImage = pNewImage;
	m_iWidth = newWidth;
	m_iHeight = newHeight;

	return true;
}

int CTGAImg::_readHeader( void ) // Examine the header and populate our class attributes
{
	short ColMapStart,ColMapLen;
	short x1,y1,x2,y2;

	if(m_pData==NULL)
		return IMG_ERR_NO_FILE;

	if(m_pData[1]>1)    // 0 (RGB) and 1 (Indexed) are the only types we know about
		return IMG_ERR_UNSUPPORTED;

	m_bEnc=m_pData[2];     // Encoding flag  1 = Raw indexed image
	//                2 = Raw RGB
	//                3 = Raw greyscale
	//                9 = RLE indexed
	//               10 = RLE RGB
	//               11 = RLE greyscale
	//               32 & 33 Other compression, indexed

	if(m_bEnc>11)       // We don't want 32 or 33
		return IMG_ERR_UNSUPPORTED;


	// Get palette info
	memcpy(&ColMapStart,&m_pData[3],2);
	memcpy(&ColMapLen,&m_pData[5],2);

	// Reject indexed images if not a VGA palette (256 entries with 24 bits per entry)
	if(m_pData[1]==1) // Indexed
	{
		if(ColMapStart!=0 || ColMapLen!=256 || m_pData[7]!=24)
			return IMG_ERR_UNSUPPORTED;
	}

	// Get image window and produce width & height values
	memcpy(&x1,&m_pData[8],2);
	memcpy(&y1,&m_pData[10],2);
	memcpy(&x2,&m_pData[12],2);
	memcpy(&y2,&m_pData[14],2);

	m_iWidth=(x2-x1);
	m_iHeight=(y2-y1);

	if(m_iWidth<1 || m_iHeight<1)
		return IMG_ERR_BAD_FORMAT;

	// Bits per Pixel
	m_iBPP=m_pData[16];

	// Check flip / interleave byte
	if(m_pData[17]>32) // Interleaved data
		return IMG_ERR_UNSUPPORTED;

	// Calculate image size
	m_lImageSize=(m_iWidth * m_iHeight * (m_iBPP/8));

	return IMG_OK;
}

int CTGAImg::_loadRawData( void ) // Load uncompressed image data
{
	short iOffset;

	if(m_pImage) // Clear old data if present
		delete [] m_pImage;

	m_pImage=new unsigned char[m_lImageSize];

	if(m_pImage==NULL)
		return IMG_ERR_MEM_FAIL;

	iOffset=m_pData[0]+18; // Add header to ident field size

	if(m_pData[1]==1) // Indexed images
		iOffset+=768;  // Add palette offset

	memcpy(m_pImage,&m_pData[iOffset],m_lImageSize);

	return IMG_OK;
}

int CTGAImg::_loadTgaRLEData( void ) // Load RLE compressed image data
{
	short iOffset,iPixelSize;
	unsigned char *pCur;
	unsigned long Index=0;
	unsigned char bLength,bLoop;

	// Calculate offset to image data
	iOffset=m_pData[0]+18;

	// Add palette offset for indexed images
	if(m_pData[1]==1)
		iOffset+=768; 

	// Get pixel size in bytes
	iPixelSize=m_iBPP/8;

	// Set our pointer to the beginning of the image data
	pCur=&m_pData[iOffset];

	// Allocate space for the image data
	if(m_pImage!=NULL)
		delete [] m_pImage;

	m_pImage=new unsigned char[m_lImageSize];

	if(m_pImage==NULL)
		return IMG_ERR_MEM_FAIL;

	// Decode
	while(Index<m_lImageSize) 
	{
		if(*pCur & 0x80) // Run length chunk (High bit = 1)
		{
			bLength=*pCur-127; // Get run length
			pCur++;            // Move to pixel data  

			// Repeat the next pixel bLength times
			for(bLoop=0;bLoop!=bLength;++bLoop,Index+=iPixelSize)
				memcpy(&m_pImage[Index],pCur,iPixelSize);

			pCur+=iPixelSize; // Move to the next descriptor chunk
		}
		else // Raw chunk
		{
			bLength=*pCur+1; // Get run length
			pCur++;          // Move to pixel data

			// Write the next bLength pixels directly
			for(bLoop=0;bLoop!=bLength;++bLoop,Index+=iPixelSize,pCur+=iPixelSize)
				memcpy(&m_pImage[Index],pCur,iPixelSize);
		}
	}

	return IMG_OK;
}

int CTGAImg::_loadTgaPalette( void ) // Load a 256 color palette
{
	unsigned char bTemp;
	short iIndex,iPalPtr;

	// Delete old palette if present
	if(m_pPalette)
	{
		delete [] m_pPalette;
		m_pPalette=NULL;
	}

	// Create space for new palette
	m_pPalette=new unsigned char[768];

	if(m_pPalette==NULL)
		return IMG_ERR_MEM_FAIL;

	// VGA palette is the 768 bytes following the header
	memcpy(m_pPalette,&m_pData[m_pData[0]+18],768);

	// Palette entries are BGR ordered so we have to convert to RGB
	for(iIndex=0,iPalPtr=0;iIndex!=256;++iIndex,iPalPtr+=3)
	{
		bTemp=m_pPalette[iPalPtr];               // Get Blue value
		m_pPalette[iPalPtr]=m_pPalette[iPalPtr+2]; // Copy Red to Blue
		m_pPalette[iPalPtr+2]=bTemp;             // Replace Blue at the end
	}

	return IMG_OK;
}

void CTGAImg::_BGRtoRGB( void ) // Convert BGR to RGB (or back again)
{
	unsigned long Index,nPixels;
	unsigned char *bCur;
	unsigned char bTemp;
	short iPixelSize;

	// Set ptr to start of image
	bCur=m_pImage;

	// Calc number of pixels
	nPixels=m_iWidth*m_iHeight;

	// Get pixel size in bytes
	iPixelSize=m_iBPP/8;

	for(Index=0;Index!=nPixels;Index++)  // For each pixel
	{
		bTemp=*bCur;      // Get Blue value
		*bCur=*(bCur+2);  // Swap red value into first position
		*(bCur+2)=bTemp;  // Write back blue to last position

		bCur+=iPixelSize; // Jump to next pixel
	}
}

unsigned char *CTGAImg::_getPixel(int x, int y)
{
	if ( x < 0 ) x = 0;
	if ( x >= m_iWidth ) x = m_iWidth-1;
	if ( y < 0 ) y = 0;
	if ( y >= m_iHeight ) y = m_iHeight-1;

	int bytes_per_pixel = m_iBPP / 8;
	int loc = (y * m_iWidth + x) * bytes_per_pixel;

	return m_pImage + loc;
}

//-----------------------------
// class CWordTable::CText
//-----------------------------
CWordTable::CText::CText( void ) : 
m_uiASCII_ID(-1), //No ASCII incode 0xFFFFFFFF (-1)
m_fWidth(8),
m_fHeight(12)
{
    _calVertexPos();
}

CWordTable::CText::CText( float fWidth, float fHeight ) :
m_uiASCII_ID(-1), //No ASCII incode 0xFFFFFFFF (-1)
m_fWidth(fWidth),
m_fHeight(fHeight)
{
    _calVertexPos();
}

void CWordTable::CText::_calVertexPos( void )
{
    m_Vertexs[0].m_fX = 0;        m_Vertexs[0].m_fY =  0;         m_Vertexs[0].m_fZ = 0;
    m_Vertexs[1].m_fX = 0;        m_Vertexs[1].m_fY = -m_fHeight; m_Vertexs[1].m_fZ = 0;
    m_Vertexs[2].m_fX = m_fWidth; m_Vertexs[2].m_fY =  0;         m_Vertexs[2].m_fZ = 0;
    m_Vertexs[3].m_fX = m_fWidth; m_Vertexs[3].m_fY = -m_fHeight; m_Vertexs[3].m_fZ = 0;
}

//-----------------------------
// class CWordTable
//-----------------------------
CWordTable::CWordTable( void ) :
m_TGAImgLoader(),
m_vectWord(),
m_eLoadingState(IMG_ERR_NO_FILE),
m_iWIDTH_OF_TXT(25),
m_iHEIGHT_OF_TXT(25),
m_iWIDTH_OF_TEXTURE(400),
m_iHEIGHT_OF_TEXTURE(150),
m_iPER_PIXEL_BYTES(4)
{
    _initial();
}

CWordTable::~CWordTable()
{
    _uninitial();
}

void CWordTable::parserString( const char* String, int& iBufferSizeInByte, int& iIBufferSizeInByte )
{
    //-------------------------------
    // Calculate Number of Text:
    //-------------------------------
    m_vectWord.clear();
    const char* pStr = String;
    while( *pStr != 0 )
    {
        unsigned int uiChar = *pStr;
        std::map<unsigned int, CText*>::iterator pIte = m_mapASCIITable.find(uiChar);
        if( pIte == m_mapASCIITable.end() )
        {
            CText* pTxt = m_mapASCIITable[0x3F]; //ASCII: '?' = 0x3F
            m_vectWord.push_back( pTxt );
        }
        else
            m_vectWord.push_back( pIte->second );

        pStr++;
    }

    //-------------------------------
    // Calculate Data buffer:
    //-------------------------------
    int iSize = static_cast<int>(m_vectWord.size());
    iBufferSizeInByte = ( iSize * 4 * sizeof(SVertex) );

    //-------------------------------
    // Calculate IndexData buffer:
    //-------------------------------   
    iIBufferSizeInByte = ( iSize * 6 * sizeof(unsigned short) );
}

void CWordTable::copyStringFrom( float* ppOutVBuffer, int iCopyMaxVBSizeInByte, unsigned short* ppOutIBuffer, int iCopyMaxIBSizeInByte )
{
    int iSize = static_cast<int>(m_vectWord.size());
    int iVBSizeInByte = ( iSize * 4 * sizeof(SVertex) );
    if( iVBSizeInByte > iCopyMaxVBSizeInByte )
    {
        iVBSizeInByte = iCopyMaxVBSizeInByte;
        iSize = iVBSizeInByte / (iSize * 4 * sizeof(SVertex));
    }

    //-------------------------------
    // Calculate Data buffer:
    //-------------------------------
    float fOffset = 0;
    float* pVTemp = ppOutVBuffer;
    for( int i=0; i<iSize; i++ )
    {
        SVertex V0 = *(m_vectWord[i]->getVertex(0));
        SVertex V1 = *(m_vectWord[i]->getVertex(1));
        SVertex V2 = *(m_vectWord[i]->getVertex(2));
        SVertex V3 = *(m_vectWord[i]->getVertex(3));

        V0.m_fX += fOffset; V1.m_fX += fOffset; V2.m_fX += fOffset; V3.m_fX += fOffset;
        fOffset += m_vectWord[i]->getWidth();

        memcpy( pVTemp, &V0, sizeof(SVertex) ); pVTemp += 5;
        memcpy( pVTemp, &V1, sizeof(SVertex) ); pVTemp += 5;
        memcpy( pVTemp, &V2, sizeof(SVertex) ); pVTemp += 5;
        memcpy( pVTemp, &V3, sizeof(SVertex) ); pVTemp += 5;
    }

    //-------------------------------
    // Calculate IndexData buffer:
    //-------------------------------
    unsigned short uiOffset = 0;
    unsigned short* pITemp = ppOutIBuffer;
    for( int i=0; i<iSize; i++ )
    {
        unsigned short usIndex[6] = { 2, 0, 1, 2, 1, 3 };
        usIndex[0] += uiOffset; usIndex[1] += uiOffset; usIndex[2] += uiOffset;
        usIndex[3] += uiOffset; usIndex[4] += uiOffset; usIndex[5] += uiOffset;

        memcpy( pITemp, usIndex, sizeof(usIndex) ); pITemp += 6;
        uiOffset += 4;
    }
}

int CWordTable::loadTGAImg( const char* sFilename, int iWidthOfTxt, int iHeightOfTxt )
{
    IMG_RESULT enumResult = m_eLoadingState = static_cast<IMG_RESULT>( m_TGAImgLoader.load( sFilename ) );
    if( enumResult == IMG_OK )
    {
        m_TGAImgLoader.flipImg();
        m_iWIDTH_OF_TXT = iWidthOfTxt;
        m_iHEIGHT_OF_TXT = iHeightOfTxt;
        m_iWIDTH_OF_TEXTURE = m_TGAImgLoader.getWidth();
        m_iHEIGHT_OF_TEXTURE = m_TGAImgLoader.getHeight();
        m_iPER_PIXEL_BYTES = m_TGAImgLoader.getBPP() / 8;

        _calTxtCoord();
    }

    return enumResult;
}

unsigned char* CWordTable::getImgData( void )
{
    if( m_eLoadingState == IMG_OK )
        return m_TGAImgLoader.getImg();
    else
        return reinterpret_cast<unsigned char*>(m_uiASCIITexture);
}

int CWordTable::getImgSize( void )
{
    return (m_iWIDTH_OF_TEXTURE * m_iHEIGHT_OF_TEXTURE * m_iPER_PIXEL_BYTES);
}

int CWordTable::getImgWidth( void )
{
    return m_iWIDTH_OF_TEXTURE;
}

int CWordTable::getImgHeight( void )
{
    return m_iHEIGHT_OF_TEXTURE;
}

int CWordTable::getBPP( void )
{
    return m_iPER_PIXEL_BYTES;
}

void CWordTable::_initial( void )
{
    typedef std::pair<unsigned int, CText*> Int_Pair;

    //---------------------------------------------
    // ASCII from 'SAPCE (32)' to 'DEL (127)':
    //---------------------------------------------
    for(int i=32; i<128; i++)
    {
        CText* txt = new CText();
        txt->setASCII_ID( static_cast<char>(i) );
        m_mapASCIITable.insert( Int_Pair( i, txt ) );       
    }

    //---------------------------------------------
    // Copy default texture:
    //---------------------------------------------
    memcpy( m_uiASCIITexture, ASCIITexture, sizeof( m_uiASCIITexture ) );

    //---------------------------------------------
    // Calculate default texture coord:
    //---------------------------------------------
    _calTxtCoord();
}

void CWordTable::_uninitial( void )
{
    for(int i=32; i<128; i++)
    {
        if( m_mapASCIITable[i] )
        {
            delete m_mapASCIITable[i];
            m_mapASCIITable[i] = NULL;
        }
    }

    m_vectWord.clear();
    m_mapASCIITable.clear();
}

void CWordTable::_calTxtCoord( void )
{
    int iUOffset = 0;
    int iVOffset = m_iHEIGHT_OF_TEXTURE;
    int iCount = 0;

    for(int i=32; i<128; i++)
    {
        CText* txt = m_mapASCIITable[i];

        if( iCount == (m_iWIDTH_OF_TEXTURE / m_iWIDTH_OF_TXT) )
        {
            iUOffset = 0;
            iVOffset -= m_iHEIGHT_OF_TXT;
            iCount = 0;
        }

        //-------------------------
        // Calculate txt coord:
        //-------------------------
        txt->getVertex(3)->m_fU = iUOffset + static_cast<float>(m_iWIDTH_OF_TXT); txt->getVertex(3)->m_fV = iVOffset - static_cast<float>(m_iHEIGHT_OF_TXT);
        txt->getVertex(0)->m_fU = txt->getVertex(3)->m_fU - m_iWIDTH_OF_TXT;      txt->getVertex(0)->m_fV = txt->getVertex(3)->m_fV + m_iHEIGHT_OF_TXT;
        txt->getVertex(1)->m_fU = txt->getVertex(3)->m_fU - m_iWIDTH_OF_TXT;      txt->getVertex(1)->m_fV = txt->getVertex(3)->m_fV;
        txt->getVertex(2)->m_fU = txt->getVertex(3)->m_fU;                        txt->getVertex(2)->m_fV = txt->getVertex(3)->m_fV + m_iHEIGHT_OF_TXT;

        //--------------------------------------
        // Normalize txt coord to 0.0~1.0:
        //--------------------------------------
        txt->getVertex(3)->m_fU /= static_cast<float>(m_iWIDTH_OF_TEXTURE); txt->getVertex(3)->m_fV /= static_cast<float>(m_iHEIGHT_OF_TEXTURE);
        txt->getVertex(2)->m_fU /= static_cast<float>(m_iWIDTH_OF_TEXTURE); txt->getVertex(2)->m_fV /= static_cast<float>(m_iHEIGHT_OF_TEXTURE);
        txt->getVertex(1)->m_fU /= static_cast<float>(m_iWIDTH_OF_TEXTURE); txt->getVertex(1)->m_fV /= static_cast<float>(m_iHEIGHT_OF_TEXTURE);
        txt->getVertex(0)->m_fU /= static_cast<float>(m_iWIDTH_OF_TEXTURE); txt->getVertex(0)->m_fV /= static_cast<float>(m_iHEIGHT_OF_TEXTURE);

        iUOffset += m_iWIDTH_OF_TXT;
        iCount++;               
    }
}

//-----------------------------
// class CWordsSystem
//-----------------------------
#define TEXTS_SHADER "\n\
float4x4  g_ViewProjMatrix;	            \n\
float4    g_TextColor;                  \n\
sampler2D g_Sampler;                    \n\
struct VSInput			                \n\
{						                \n\
    float3 position : POSITION;	        \n\
    float2 texcoord : TEXCOORD;	        \n\
};						                \n\
struct VSOutput			                \n\
{						                \n\
    float4 position : POSITION;	        \n\
    float2 texcoord : TEXCOORD;	        \n\
};						                \n\
VSOutput vs_main(VSInput In)	        \n\
{						                \n\
    VSOutput Out;		                \n\
    float4 Pos = float4(In.position, 1);  \n\
    Out.position = mul( g_ViewProjMatrix, Pos );\n\
    Out.texcoord = In.texcoord;		      \n\
    return Out;			                  \n\
}						                  \n\
float4 ps_main(VSOutput In):COLOR0        \n\
{						                  \n\
    float4 f4Color = tex2D( g_Sampler, In.texcoord ); \n\
    return (f4Color * g_TextColor);	      \n\
};\n"

CWordSystem::CWordSystem( void ) :
m_pRenderDeviceRef(NULL),
m_pVDeclObj(NULL),
m_pVSObj(NULL),
m_pPSObj(NULL),
m_pTextObj(NULL),
m_Sampler()
{
}

CWordSystem::~CWordSystem( void )
{
}

bool CWordSystem::initial( CRenderDevice* pRenderDevice, const char* sFilename )
{
    m_pRenderDeviceRef = pRenderDevice;
    SVertexElement VertexElements[] = { SVertexElement( "POSITION", 0,  E_VERTEXELETYPE_FLOAT3, 0, 0 ),
                                        SVertexElement( "TEXCOORD", 0,  E_VERTEXELETYPE_FLOAT2, 12, 0 ),
                                        SVertexElement( VE_END() ) };

    m_pVDeclObj = m_pRenderDeviceRef->createVertexDeclObject( VertexElements );
    m_pVSObj    = m_pRenderDeviceRef->createShaderObjectFromText( E_SHADERTYPE_VERTEX, TEXTS_SHADER, "vs_main", NULL );
    m_pPSObj    = m_pRenderDeviceRef->createShaderObjectFromText( E_SHADERTYPE_PIXEL, TEXTS_SHADER, "ps_main", NULL );

    CTexture2DObject::STexture2DDesc Desc( 1, m_WordTable.getImgWidth(), m_WordTable.getImgHeight(), 0, E_INTERFORMAT_RGBA );
    m_pTextObj = m_pRenderDeviceRef->createTexture2DObject( Desc );
    if( m_pVDeclObj && m_pVSObj && m_pPSObj && m_pTextObj )
    {
        if( pRenderDevice->compileShader(m_pVSObj, false) == E_SUCCESS &&
            pRenderDevice->compileShader(m_pPSObj, false) == E_SUCCESS)
        {
            if( m_pTextObj->setData( 0, 0, 0, m_WordTable.getImgWidth(), m_WordTable.getImgHeight(), E_DATAFORMAT_RGBA_UBYTE, (void*)m_WordTable.getImgData() ) == E_SUCCESS )
                return true;
        }
    }

    uninitial();
    return false;
}

void CWordSystem::uninitial( void )
{
    if( m_pVDeclObj )
        m_pRenderDeviceRef->destroyVertexDeclObject( &m_pVDeclObj );

    if( m_pVSObj )
        m_pRenderDeviceRef->destroyShaderObject( &m_pVSObj );

    if( m_pPSObj )
        m_pRenderDeviceRef->destroyShaderObject( &m_pPSObj );

    if( m_pTextObj )
        m_pRenderDeviceRef->destroyTextureObject( &m_pTextObj );
}

void CWordSystem::setOrthoL( float left, float right, float bottom, float top, float nearVal, float farVal, float* pM )
{
    float Tx, Ty, Tz;
    Tx = -( (right + left) / (right - left) );
    Ty = -( (top + bottom) / (top - bottom) );
    Tz = -( (farVal + nearVal) / (farVal - nearVal) );

    pM[0] = 2.0f / (right - left);
    pM[1] = 0.0f;
    pM[2] = 0.0f;
    pM[3] = Tx;

    pM[4] = 0.0f;
    pM[5] = 2.0f / (top - bottom);
    pM[6] = 0.0f;
    pM[7] = Ty;

    pM[8] = 0.0f;
    pM[9] = 0.0f;
    pM[10] = -2.0f / (farVal - nearVal);
    pM[11] = Tz;

    pM[12] = 0.0f;
    pM[13] = 0.0f;
    pM[14] = 0.0f;
    pM[15] = 1.0f;
}

void CWordSystem::mulMatrix( const float* pM1, const float* pM2, float* pOut )
{
    pOut[0]  = pM1[0]*pM2[0] + pM1[1]*pM2[4] + pM1[2]*pM2[8]  + pM1[3]*pM2[12];
    pOut[1]  = pM1[0]*pM2[1] + pM1[1]*pM2[5] + pM1[2]*pM2[9]  + pM1[3]*pM2[13];
    pOut[2]  = pM1[0]*pM2[2] + pM1[1]*pM2[6] + pM1[2]*pM2[10] + pM1[3]*pM2[14];
    pOut[3]  = pM1[0]*pM2[3] + pM1[1]*pM2[7] + pM1[2]*pM2[11] + pM1[3]*pM2[15];

    pOut[4]  = pM1[4]*pM2[0] + pM1[5]*pM2[4] + pM1[6]*pM2[8]  + pM1[7]*pM2[12];
    pOut[5]  = pM1[4]*pM2[1] + pM1[5]*pM2[5] + pM1[6]*pM2[9]  + pM1[7]*pM2[13];
    pOut[6]  = pM1[4]*pM2[2] + pM1[5]*pM2[6] + pM1[6]*pM2[10] + pM1[7]*pM2[14];
    pOut[7]  = pM1[4]*pM2[3] + pM1[5]*pM2[7] + pM1[6]*pM2[11] + pM1[7]*pM2[15];

    pOut[8]  = pM1[8]*pM2[0] + pM1[9]*pM2[4] + pM1[10]*pM2[8] + pM1[11]*pM2[12];
    pOut[9]  = pM1[8]*pM2[1] + pM1[9]*pM2[5] + pM1[10]*pM2[9] + pM1[11]*pM2[13];
    pOut[10] = pM1[8]*pM2[2] + pM1[9]*pM2[6] + pM1[10]*pM2[10]+ pM1[11]*pM2[14];
    pOut[11] = pM1[8]*pM2[3] + pM1[9]*pM2[7] + pM1[10]*pM2[11]+ pM1[11]*pM2[15];

    pOut[12] = pM1[12]*pM2[0]+ pM1[13]*pM2[4]+ pM1[14]*pM2[8] + pM1[15]*pM2[12];
    pOut[13] = pM1[12]*pM2[1]+ pM1[13]*pM2[5]+ pM1[14]*pM2[9] + pM1[15]*pM2[13];
    pOut[14] = pM1[12]*pM2[2]+ pM1[13]*pM2[6]+ pM1[14]*pM2[10]+ pM1[15]*pM2[14];
    pOut[15] = pM1[12]*pM2[3]+ pM1[13]*pM2[7]+ pM1[14]*pM2[11]+ pM1[15]*pM2[15];
}

}//End namespace GL

}//End namespace Porman
